#include <errno.h>

#include <linux/sched.h>
#include <linux/kernel.h>
#include <asm/system.h>

long last_pid = 0;

int copy_mem(int nr, struct task_struct *p)
{
    unsigned long old_data_base, new_data_base, data_limit;
    unsigned long old_code_base, new_code_base, code_limit;

    code_limit = get_limit(0x0f);
    data_limit = get_limit(0x17);
    old_code_base = get_base(current->ldt[1]);
    old_data_base = get_base(current->ldt[2]);
    if (old_data_base != old_code_base)
        panic("We don't support separate I&D");
    if (data_limit < code_limit)
        panic("Bad data_limit");
    new_data_base = new_code_base = nr * 0x4000000; // 新基址 = 任务号 * 64MB（任务大小）
    p->start_code = new_code_base;
    set_base(p->ldt[1], new_code_base); // 设置代码段基址
    set_base(p->ldt[2], new_data_base); // 设置数据段基址
    if (copy_page_tables(old_data_base, new_data_base, data_limit)) {
        printk("free_page_tables: from copy_mem\n\r");
        free_page_tables(new_data_base, data_limit);
        return -ENOMEM;
    }
    return 0;
}

int copy_process(int nr, long ebp, long edi, long esi, long gs,
        long none, long ebx, long ecx, long edx,
        long fs, long es, long ds, long eip,
        long cs, long eflags, long esp, long ss)
{
    struct task_struct *p;

    p = (struct task_struct *) get_free_page();
    if (!p)
        return -EAGAIN;
    task[nr] = p;
    __asm__("cld"::);   // 必须添加这一句，否则下一句不能正确执行
    *p = *current;      // 复制父进程的参数
    p->state = TASK_UNINTERRUPTIBLE;
    p->pid = last_pid;  // 由find_emtpy_process找到的pid
    p->father = current->pid;   // 设置父进程号
    p->counter = p->priority;
    p->signal = 0;
    p->alarm = 0;
    p->leader = 0;
    p->utime = p->stime = 0;    // 初始化用户态时间和核心态时间
    p->cutime = p->cstime = 0;  // 初始化子进程用户态和核心态时间
    p->start_time = jiffies;    // 当前滴答数时间
    // 以下设置任务状态段tss所需的参数
    p->tss.back_link = 0;
    p->tss.esp0 = PAGE_SIZE + (long) p;
    p->tss.ss0 = 0x10;
    p->tss.eip = eip;
    p->tss.eflags = eflags;
    p->tss.eax = 0;
    p->tss.ecx = ecx;
    p->tss.edx = edx;
    p->tss.ebx = ebx;
    p->tss.esp = esp;
    p->tss.ebp = ebp;
    p->tss.esi = esi;
    p->tss.edi = edi;
    p->tss.es = es & 0xffff;    // 段寄存器仅16位有效
    p->tss.cs = cs & 0xffff;
    p->tss.ss = ss & 0xffff;
    p->tss.ds = ds & 0xffff;
    p->tss.fs = fs & 0xffff;
    p->tss.gs = gs & 0xffff;
    p->tss.ldt = _LDT(nr);      // 新任务的局部描述符表选择符
    p->tss.trace_bitmap = 0x80000000;
    if (last_task_used_math == current)
        __asm__("clts\n\tfnsave %0"::"m"(p->tss.i387));
    if (copy_mem(nr, p)) {
        task[nr] = NULL;
        free_page((long) p);
        return -EAGAIN;
    }
    // 设置新任务的tss和ldt描述符
    set_tss_desc(gdt + (nr << 1) + FIRST_TSS_ENTRY, &(p->tss));
    set_ldt_desc(gdt + (nr << 1) + FIRST_LDT_ENTRY, &(p->ldt));
    p->state = TASK_RUNNING;    // 将任务设置为可运行状态

    return last_pid;
}

int find_empty_process(void)
{
    int i;

repeat: // 获取不重复的pid
    if ((++last_pid) < 0)
        last_pid = 1;
    for(i = 0; i < NR_TASKS; i++)
        if (task[i] && task[i]->pid == last_pid)
            goto repeat;
    for(i = 1; i < NR_TASKS; i++)   // 把任务0排除在外
        if (!task[i])
            return i;
    return -EAGAIN;
}